﻿#ifndef DRAWER_H
#define DRAWER_H

#define GLFW_INCLUDE_NONE
#define _CRT_SECURE_NO_WARNINGS

#define M_PI 3.14159265358979323846

#include "BaseTypes.h"
#include "Utils.h"

#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "glad/glad.h"

#include <opencv2/opencv.hpp>

#include <vector>
#include <cmath>
#include <random>

#include <ft2build.h>
#include FT_FREETYPE_H

struct Sector {
    GLuint vao;
    GLuint vbo;
    GLuint tempTex;
    GLuint tempFbo;
    GLuint msaaFbo;
    GLuint colorTex;
    GLuint resolveFbo;
    GLuint resolveTex;
    GLuint depthRbo;
    float maxRadius;
    float centerX;
    float centerY;
    int vertexCount;
    size_t width;
    size_t height;
};

struct Vertex {
    float dx, dy;
    float radiusRatio;
};

struct SharedFramebuffer {
    GLuint msaaFBO;        // 多重采样FBO
    GLuint resolveFBO;     // 解析用FBO
    GLuint colorTex;       // 最终纹理
    GLuint colorRBO;       // 多重采样颜色缓冲
    GLuint depthRBO;       // 多重采样深度缓冲
    int width;
    int height;
};

struct DoubleSector {
    GLuint VAO;
    GLuint VBO;
    int vertexCount;
    float startDuration;
    float endDuration;
    unsigned char r, g, b, a;
    float centerX, centerY;
    float maxRadius;
    float borderBrightness;
    float centerBrightness;
    float borderRadius;
    float middleColorLoc;
    float angleRange[2];
};

struct DoubleSectorVertex {
    float angle; // 弧度
    float type;  // 0.0内圈，1.0外圈
};

// GPU顶点数据结构
typedef struct Particle {
    glm::vec2 position;
    glm::vec2 velocity;
    glm::vec2 acceleration;
    int life;
    float radius;
}Particle;

typedef struct ParticleSystem {
    std::vector<Particle> particles;
    GLuint VAO, VBO, FBO, texture, resolveTexture, tempTex, msaaFBO, tempFBO;
    glm::vec4 color;
    float width, height, frameRate, initCircleRadius;
    glm::vec2 initRadius, lifeRange;
    glm::vec2 center;
    glm::vec2 velRange, accelDeltaRange, accelAngleRange, initAngleRange;
    glm::mat4 projection;
}ParticleSystem;

struct GaussianBlurKernel {
    std::vector<float> weights;
    GLuint horizontalFBO;
    GLuint horizontalTexture;
    GLuint shaderProgram;
    GLint uWeights;
    GLint uDirection;
    GLint uTextureSize;
    GLuint quadVAO;
    size_t kernelSize;
    size_t frameWidth;
    size_t frameHeight;
    int radius;
};

struct RecordVertex {
    glm::vec2 position;
    glm::vec2 texCoord;
};

struct Record {
    GLuint layer0_vao, layer0_vbo, layer0_tex;
    GLuint layer1_vao, layer1_vbo, layer1_tex;
    GLuint merged_vao, merged_vbo, merged_tex;
    float current_angle;
    float delta_angle;
    float frame_width, frame_height;
    GLuint shader_program;
    GLuint fbo;          // 新增：离屏渲染的帧缓冲对象
    GLuint fbo_texture;  // 新增：FBO的颜色附件纹理
    GLuint rbo;          // 新增：渲染缓冲对象（用于深度/模板测试）
};

enum class Anchor {
    NW,
    N,
    NE,
    W,
    CENTER,
    E,
    SW,
    S,
    SE,
    FREE
};

enum class TextAlignment {
    LEFT,
    CENTER,
    RIGHT,
    TOP,
    BOTTOM
};

struct Text {
    FT_Face font;
    GLuint vao, vbo;
    GLuint shader_program;
    glm::mat4 projection;
    float loc_x, loc_y;
    float anchor_x, anchor_y;
    int frame_size_x, frame_size_y;
    Color color;
    uint8_t alpha;
    bool horizontal;
    float line_spacing;
    TextAlignment alignment;
};

namespace Drawer {
    void initGL(size_t width, size_t height);
    Sector initSector(size_t width, size_t height, double startAngle, double endAngle, double lightExtension, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
    void drawSector(GLuint shaderProgram, Sector sector, size_t radius);
    SharedFramebuffer initSharedFramebuffer(int width, int height);
    std::vector<DoubleSector> initDoubleSector(
        int width, int height,
        float* startAngle, float* endAngle,
        unsigned char* r, unsigned char* g, unsigned char* b, unsigned char a,
        size_t* startDuration, size_t* endDuration, size_t doubleSectorNum,
        float borderBrightness, float centerBrightness, float borderRadius,
        float middleColorLoc
    );

    void drawDoubleSector(GLuint shaderProgram, std::vector<DoubleSector> &doubleSector, size_t currentDuration,
                          SharedFramebuffer &m_sharedFB, float end_radius, float max_radius, int &sectorMinIndex);

    ParticleSystem initParticles(
        glm::vec2 initRadius,
        glm::vec4 color,
        glm::vec2 lifeRange,
        float initCircleRadius,
        glm::vec2 velRange,
        glm::vec2 initAngleRange,
        glm::vec2 accelDeltaRange,
        glm::vec2 accelAngleRange,
        int particleTotal,
        float width,
        float height,
        float frameRate
    );
    void updateAndDrawParticles(
        GLuint shaderProgram,
        ParticleSystem& system,
        size_t particleCount
    );
    GaussianBlurKernel createGaussianBlurKernel(float blur_sigma, GLuint shader_program, size_t frame_width, size_t frame_height);
    void applyGaussianBlur(GaussianBlurKernel& kernel, GLuint fbo, GLuint rbo, GLuint texture);
    Record initRecord(cv::Mat& layer0, cv::Mat& layer1, cv::Mat& layer2, cv::Mat& layer3,
        cv::Mat& record_pic, GLuint shader_program, float dps,
        float fw, float fh, float fr);
    void drawRecord(Record& rec);
    Text initText(
        FT_Face& font,
        Color color, 
        uint8_t alpha,
        float frame_size_x, 
        float frame_size_y, 
        int loc_x, 
        int loc_y, 
        Anchor anchor,
        float anchor_x,
        float anchor_y,
        bool horizontal,
        float line_spacing,
        TextAlignment alignment,
        GLuint shader_program
    );
    void drawText(Text& text, std::string name, GLuint target_fbo, GLuint target_texture);
}

#endif